package com.fans.common.utils;

import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringEscapeUtils;


/**
 * @ClassName: StringUtils
 * @Description: 字符串工具类, 继承org.apache.commons.lang3.StringUtils类
 * @author fanhaohao
 * @date 2019年12月13日 下午4:49:03
 */
public class StringUtils extends org.apache.commons.lang3.StringUtils{

    private static final char SEPARATOR = '_';
    private static final String CHARSET_NAME = "UTF-8";
	/** 空字符串 */
	private static final String NULLSTR = "";

    /**
     * 验证字符串是否有效
     * @param str 验证字符串
     * @return 不为空切不包含非空字符返回<code>true</code>
     * @see java.lang.Character#isWhitespace
     */

    public static boolean hasText(String str){
        if(!hasLength(str)){
            return false;
        }

        int strLen = str.length();

        for(int i = 0 ; i < strLen ; i++){
            if(!Character.isWhitespace(str.charAt(i))){
                return true;
            }
        }

        return false;
    }

    /**
     * 验证字符串是否为空或长度为0
     * @param str 验证字符串
     * @return 如果字符串不为空并且长度大于0返回<code>true</code>
     * @see #hasText(String)
     */
    public static boolean hasLength(String str){
        return (str != null && str.length() > 0);
    }

    /**
     * 转换为字节数组
     * @param str
     * @return
     */
    public static byte[] getBytes(String str){
        if(str != null){
            try{
                return str.getBytes(CHARSET_NAME);
            }catch (UnsupportedEncodingException e){
                return null;
            }
        }else{
            return null;
        }
    }

    /**
     * 转换为字节数组
     * @param str
     * @return
     */
    public static String toString(byte[] bytes){
        try{
            return new String(bytes, CHARSET_NAME);
        }catch (UnsupportedEncodingException e){
            return EMPTY;
        }
    }

    /**
     * 是否包含字符串
     * @param str 验证字符串
     * @param strs 字符串组
     * @return 包含返回true
     */
    public static boolean inString(String str, String ... strs){
        if(str != null){
            for(String s : strs){
                if(str.equals(trim(s))){
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 替换掉HTML标签方法
     */
    public static String replaceHtml(String html){
        if(isBlank(html)){
            return "";
        }
        String regEx = "<.+?>";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(html);
        String s = m.replaceAll("");
        return s;
    }

    /**
     * 替换为手机识别的HTML，去掉样式及属性，保留回车。
     * @param html
     * @return
     */
    public static String replaceMobileHtml(String html){
        if(html == null){
            return "";
        }
        return html.replaceAll("<([a-z]+?)\\s+?.*?>", "<$1>");
    }

    /**
     * 替换为手机识别的HTML，去掉样式及属性，保留回车。
     * @param txt
     * @return
     */
    public static String toHtml(String txt){
        if(txt == null){
            return "";
        }
        return replace(replace(Encodes.escapeHtml(txt), "\n", "<br/>"), "\t", "&nbsp; &nbsp; ");
    }

    /**
     * 缩略字符串（不区分中英文字符）
     * @param str 目标字符串
     * @param length 截取长度
     * @return
     */
    public static String abbr(String str, int length){
        if(str == null){
            return "";
        }
        try{
            StringBuilder sb = new StringBuilder();
            int currentLength = 0;
            for(char c : replaceHtml(StringEscapeUtils.unescapeHtml4(str)).toCharArray()){
                currentLength += String.valueOf(c).getBytes("GBK").length;
                if(currentLength <= length - 3){
                    sb.append(c);
                }else{
                    sb.append("...");
                    break;
                }
            }
            return sb.toString();
        }catch (UnsupportedEncodingException e){
            e.printStackTrace();
        }
        return "";
    }

    public static String abbr2(String param, int length){
        if(param == null){
            return "";
        }
        StringBuffer result = new StringBuffer();
        int n = 0;
        char temp;
        boolean isCode = false; // 是不是HTML代码
        boolean isHTML = false; // 是不是HTML特殊字符,如&nbsp;
        for(int i = 0 ; i < param.length() ; i++){
            temp = param.charAt(i);
            if(temp == '<'){
                isCode = true;
            }else if(temp == '&'){
                isHTML = true;
            }else if(temp == '>' && isCode){
                n = n - 1;
                isCode = false;
            }else if(temp == ';' && isHTML){
                isHTML = false;
            }
            try{
                if(!isCode && !isHTML){
                    n += String.valueOf(temp).getBytes("GBK").length;
                }
            }catch (UnsupportedEncodingException e){
                e.printStackTrace();
            }

            if(n <= length - 3){
                result.append(temp);
            }else{
                result.append("...");
                break;
            }
        }
        // 取出截取字符串中的HTML标记
        String temp_result = result.toString().replaceAll("(>)[^<>]*(<?)", "$1$2");
        // 去掉不需要结素标记的HTML标记
        temp_result = temp_result.replaceAll(
            "</?(AREA|BASE|BASEFONT|BODY|BR|COL|COLGROUP|DD|DT|FRAME|HEAD|HR|HTML|IMG|INPUT|ISINDEX|LI|LINK|META|OPTION|P|PARAM|TBODY|TD|TFOOT|TH|THEAD|TR|area|base|basefont|body|br|col|colgroup|dd|dt|frame|head|hr|html|img|input|isindex|li|link|meta|option|p|param|tbody|td|tfoot|th|thead|tr)[^<>]*/?>",
            "");
        // 去掉成对的HTML标记
        temp_result = temp_result.replaceAll("<([a-zA-Z]+)[^<>]*>(.*?)</\\1>", "$2");
        // 用正则表达式取出标记
        Pattern p = Pattern.compile("<([a-zA-Z]+)[^<>]*>");
        Matcher m = p.matcher(temp_result);
		List<String> endHTML = new ArrayList();
        while (m.find()){
            endHTML.add(m.group(1));
        }
        // 补全不成对的HTML标记
        for(int i = endHTML.size() - 1 ; i >= 0 ; i--){
            result.append("</");
            result.append(endHTML.get(i));
            result.append(">");
        }
        return result.toString();
    }

    /**
     * 转换为Double类型
     */
    public static Double toDouble(Object val){
        if(val == null){
            return 0D;
        }
        try{
            return Double.valueOf(trim(val.toString()));
        }catch (Exception e){
            return 0D;
        }
    }

    /**
     * 转换为Float类型
     */
    public static Float toFloat(Object val){
        return toDouble(val).floatValue();
    }

    /**
     * 转换为Long类型
     */
    public static Long toLong(Object val){
        return toDouble(val).longValue();
    }

    /**
     * 转换为Integer类型
     */
    public static Integer toInteger(Object val){
        return toLong(val).intValue();
    }

    /**
     * 获得用户远程地址
     */
    public static String getRemoteAddr(HttpServletRequest request){
        String remoteAddr = request.getHeader("X-Real-IP");
        if(isNotBlank(remoteAddr)){
            remoteAddr = request.getHeader("X-Forwarded-For");
        }else if(isNotBlank(remoteAddr)){
            remoteAddr = request.getHeader("Proxy-Client-IP");
        }else if(isNotBlank(remoteAddr)){
            remoteAddr = request.getHeader("WL-Proxy-Client-IP");
        }
        return remoteAddr != null ? remoteAddr : request.getRemoteAddr();
    }

	/**
	 * @return 本机IP
	 * @throws SocketException
	 */
	public static String getRealIp() throws SocketException {
		String localip = null;// 本地IP，如果没有配置外网IP则返回它
		String netip = null;// 外网IP

		Enumeration<NetworkInterface> netInterfaces = NetworkInterface.getNetworkInterfaces();
		InetAddress ip = null;
		boolean finded = false;// 是否找到外网IP
		while (netInterfaces.hasMoreElements() && !finded) {
			NetworkInterface ni = netInterfaces.nextElement();
			Enumeration<InetAddress> address = ni.getInetAddresses();
			while (address.hasMoreElements()) {
				ip = address.nextElement();
				if (!ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && ip.getHostAddress().indexOf(":") == -1) {// 外网IP
					netip = ip.getHostAddress();
					finded = true;
					break;
				} else if (ip.isSiteLocalAddress() && !ip.isLoopbackAddress()
						&& ip.getHostAddress().indexOf(":") == -1) {// 内网IP
					localip = ip.getHostAddress();
				}
			}
		}

		if (netip != null && !"".equals(netip)) {
			return netip;
		} else {
			return localip;
		}
	}

    /**
     * 驼峰命名法工具
     * @return toCamelCase("hello_world") == "helloWorld"
     *         toCapitalizeCamelCase("hello_world") == "HelloWorld"
     *         toUnderScoreCase("helloWorld") = "hello_world"
     */
    public static String toCamelCase(String s){
        if(s == null){
            return null;
        }

        s = s.toLowerCase();

        StringBuilder sb = new StringBuilder(s.length());
        boolean upperCase = false;
        for(int i = 0 ; i < s.length() ; i++){
            char c = s.charAt(i);

            if(c == SEPARATOR){
                upperCase = true;
            }else if(upperCase){
                sb.append(Character.toUpperCase(c));
                upperCase = false;
            }else{
                sb.append(c);
            }
        }

        return sb.toString();
    }

    /**
     * 驼峰命名法工具
     * @return toCamelCase("hello_world") == "helloWorld"
     *         toCapitalizeCamelCase("hello_world") == "HelloWorld"
     *         toUnderScoreCase("helloWorld") = "hello_world"
     */
    public static String toCapitalizeCamelCase(String s){
        if(s == null){
            return null;
        }
        s = toCamelCase(s);
        return s.substring(0, 1).toUpperCase() + s.substring(1);
    }

    /**
     * 驼峰命名法工具
     * @return toCamelCase("hello_world") == "helloWorld"
     *         toCapitalizeCamelCase("hello_world") == "HelloWorld"
     *         toUnderScoreCase("helloWorld") = "hello_world"
     */
    public static String toUnderScoreCase(String s){
        if(s == null){
            return null;
        }

        StringBuilder sb = new StringBuilder();
        boolean upperCase = false;
        for(int i = 0 ; i < s.length() ; i++){
            char c = s.charAt(i);

            boolean nextUpperCase = true;

            if(i < (s.length() - 1)){
                nextUpperCase = Character.isUpperCase(s.charAt(i + 1));
            }

            if((i > 0) && Character.isUpperCase(c)){
                if(!upperCase || !nextUpperCase){
                    sb.append(SEPARATOR);
                }
                upperCase = true;
            }else{
                upperCase = false;
            }

            sb.append(Character.toLowerCase(c));
        }

        return sb.toString();
    }

    /**
     * 如果不为空，则设置值
     * @param target
     * @param source
     */
    public static void setValueIfNotBlank(String target, String source){
        if(isNotBlank(source)){
            target = source;
        }
    }

    /**
     * 转换为JS获取对象值，生成三目运算返回结果
     * @param objectString 对象串 例如：row.user.id
     *            返回：!row?'':!row.user?'':!row.user.id?'':row.user.id
     */
    public static String jsGetVal(String objectString){
        StringBuilder result = new StringBuilder();
        StringBuilder val = new StringBuilder();
        String[] vals = split(objectString, ".");
        for(int i = 0 ; i < vals.length ; i++){
            val.append("." + vals[i]);
            result.append("!" + (val.substring(1)) + "?'':");
        }
        result.append(val.substring(1));
        return result.toString();
    }
    /**
     * <p>
     * three type: endsWithMatch(eg. /xxx*=/xxx/xyz), startsWithMatch(eg. *.xxx=abc.xxx), equals(eg. /xxx=/xxx).
     * </p>
     * <b>Notice</b>: *xxx* will match *xxxyyyy. endsWithMatch first.
     */
    public static boolean matches(String pattern, String source) {
    	if (pattern == null || source == null) {
            return false;
        }
        pattern = pattern.trim();
        source = source.trim();
        if (pattern.startsWith("*")&&pattern.endsWith("*")) {
            // pattern: /druid* source:/druid/index.html
        	int length = pattern.length() - 1;
            String subpath = pattern.substring(1, length);
            if (source.length() >= length) {
                if (source.indexOf(subpath)>=0) {
                    return true;
                }
            }
        } else if (pattern.endsWith("*")) {
            // pattern: /druid* source:/druid/index.html
            int length = pattern.length() - 1;
            if (source.length() >= length) {
                if (pattern.substring(0, length).equals(source.substring(0, length))) {
                    return true;
                }
            }
        } else if (pattern.startsWith("*")) {
            // pattern: *.html source:/xx/xx.html
            int length = pattern.length() - 1;
            String endPart = pattern.substring(1);
            if (source.length() >= length) {
            	if(source.endsWith(endPart)) {
					return true;
				}
            	if(source.indexOf(endPart + "?") > 0) {
					return true;
				}
            }
        } else {
            // pattern: /druid/index.html source:/druid/index.html
            if (pattern.equals(source)) {
                return true;
            }
        }
        return false;
    }
    public static String genUUID() {
	    return UUID.randomUUID().toString().replaceAll("-", "");
	}
    
    /**
     * @Title：arraryToString  
     * @Description: 集合类转字符串
     * @author: fanhaohao
     * @date 2019年12月20日 下午2:36:44 
     * @param @param collection
     * @param @return 
     * @return String 
     * @throws
     */
    public static <E> String arraryToString(Collection<E> collection) {
        Iterator<E> it = collection.iterator();
        if (!it.hasNext()) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        for (; ; ) {
            E e = it.next();
            sb.append(e == collection ? "(this Collection)" : e);
            if (!it.hasNext()) {
                return sb.toString();
            }
            sb.append(',');
        }
    }

	/**
	 * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空，则返回空字符串。
	 * 例如：HELLO_WORLD->HelloWorld
	 * 
	 * @param name
	 *            转换前的下划线大写方式命名的字符串
	 * @return 转换后的驼峰式命名的字符串
	 */
	public static String convertToCamelCase(String name) {
		StringBuilder result = new StringBuilder();
		// 快速检查
		if (name == null || name.isEmpty()) {
			// 没必要转换
			return "";
		} else if (!name.contains("_")) {
			// 不含下划线，仅将首字母大写
			return name.substring(0, 1).toUpperCase() + name.substring(1);
		}
		// 用下划线将原始字符串分割
		String[] camels = name.split("_");
		for (String camel : camels) {
			// 跳过原始字符串中开头、结尾的下换线或双重下划线
			if (camel.isEmpty()) {
				continue;
			}
			// 首字母大写
			result.append(camel.substring(0, 1).toUpperCase());
			result.append(camel.substring(1).toLowerCase());
		}
		return result.toString();
	}
	/**
     * 获取参数不为空值
     * 
     * @param value defaultValue 要判断的value
     * @return value 返回值
     */
    public static <T> T nvl(T value, T defaultValue)
    {
        return value != null ? value : defaultValue;
    }

	/**
	 * 是否包含字符串
	 * 
	 * @param str
	 *            验证字符串
	 * @param strs
	 *            字符串组
	 * @return 包含返回true
	 */
	public static boolean inStringIgnoreCase(String str, String... strs) {
		if (str != null && strs != null) {
			for (String s : strs) {
				if (str.equalsIgnoreCase(trim(s))) {
					return true;
				}
			}
		}
		return false;
	}

}
